/*
@title: Catch_the_Egg
@description: Catch the Egg is a game where players must quickly move their basket under hens to catch falling eggs. The objective is to score points by catching eggs while avoiding multiple misses. The game ends when too many eggs are missed or a maximum score is reached.
@author: Jonak-Adipta-Kalita
@tags: []
@addedOn: 2024-04-18
*/

const MAX_SCORE = 1000000;
let score = 0;
let misses = 0;

const background = "z"
const basket = "b"

const chickenRight = {
  0: "r",
  1: "s",
  2: "t",
  3: "u",
  4: "v"
}

const chickenLeft = {
  0: "l",
  1: "m",
  2: "n",
  3: "o",
  4: "p",
}

const heartFull = "2"
const heartHalf = "1"
const heartEmpty = "0"

setLegend(
  [background, bitmap`
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111
1111111111111111`],
  [basket, bitmap`
.....CCCCCC.....
....CC....CC....
...CC......CC...
..CC........CC..
.CC..........CC.
CC............CC
C..............C
CCCCCCCCCCCCCCCC
C99999999999999C
CC999999999999CC
.C999CC99CC999C.
.CC9999999999CC.
..C9999CC9999C..
..CC99999999CC..
...C99999999C...
...CCCCCCCCCC...`],

  [chickenRight[0], bitmap`
....0...........
...030..........
...030..........
..02220.........
.002020.........
0662220.........
.062220.........
..032200000.....
..0322222220....
..0222222220....
...022222220....
....0000000.....
................
................
................
................`],
  [chickenRight[1], bitmap`
....0...........
...030..........
...030..........
..02220.........
.002020.........
0662220.........
.062220.........
..032200000.....
..0322222220....
..0222222220....
...022222220....
....0000000.....
............2...
................
................
................`],
  [chickenRight[2], bitmap`
....0...........
...030..........
...030..........
..02220.........
.002020.........
0662220.........
.062220.........
..032200000.....
..0322222220....
..0222222220....
...022222220....
....0000000.....
............22..
............22..
................
................`],
  [chickenRight[3], bitmap`
....0...........
...030..........
...030..........
..02220.........
.002020.........
0662220.........
.062220.........
..032200000.....
..0322222220....
..0222222220....
...022222220....
....0000000.....
............222.
............222.
............222.
................`],
  [chickenRight[4], bitmap`
....0...........
...030..........
...030..........
..02220.........
.002020.........
0662220.........
.062220.........
..032200000.....
..0322222220....
..0222222220....
...022222220....
....0000000.....
............2222
............2222
............2222
............2222`],

  [chickenLeft[0], bitmap`
...........0....
..........030...
..........030...
.........02220..
.........020200.
.........0222660
.........022260.
.....000002230..
....0222222230..
....0222222220..
....022222220...
.....0000000....
................
................
................
................`],
  [chickenLeft[1], bitmap`
...........0....
..........030...
..........030...
.........02220..
.........020200.
.........0222660
.........022260.
.....000002230..
....0222222230..
....0222222220..
....022222220...
.....0000000....
...2............
................
................
................`],
  [chickenLeft[2], bitmap`
...........0....
..........030...
..........030...
.........02220..
.........020200.
.........0222660
.........022260.
.....000002230..
....0222222230..
....0222222220..
....022222220...
.....0000000....
..22............
..22............
................
................`],
  [chickenLeft[3], bitmap`
...........0....
..........030...
..........030...
.........02220..
.........020200.
.........0222660
.........022260.
.....000002230..
....0222222230..
....0222222220..
....022222220...
.....0000000....
.222............
.222............
.222............
................`],
  [chickenLeft[4], bitmap`
...........0....
..........030...
..........030...
.........02220..
.........020200.
.........0222660
.........022260.
.....000002230..
....0222222230..
....0222222220..
....022222220...
.....0000000....
2222............
2222............
2222............
2222............`],

  [heartFull, bitmap`
................
................
................
................
................
...333....333...
..33333..33333..
...333....333...
....3......3....
................
................
................
................
................
................
................`],
  [heartHalf, bitmap`
................
................
................
................
................
...333....333...
..33333..3...3..
...333....3.3...
....3......3....
................
................
................
................
................
................
................`],
  [heartEmpty, bitmap`
................
................
................
................
................
...333....333...
..3...3..3...3..
...3.3....3.3...
....3......3....
................
................
................
................
................
................
................`],
)

playTune(tune`
200: E4/200 + A4-200 + E5~200,
200,
200: E4/200 + B4-200 + E5~200,
200,
200: D4/200 + B4-200 + E5~200,
200: B4-200 + E5~200 + G5^200,
200: E4/200 + B4-200 + E5~200,
200,
200: E4/200 + B4-200 + E5~200,
200,
200: E4/200 + B4-200 + E5~200,
200,
200: D4/200 + A4-200 + D5~200 + F5^200,
200,
200: E4/200 + B4-200 + E5~200,
200: C5-200 + F5~200 + A5^200,
200: E4/200 + B4-200 + E5~200,
200,
200: E4/200 + B4-200 + E5~200,
200,
200: D4/200 + A4-200 + D5~200,
200: B4-200 + E5~200,
200: E4/200 + C5-200 + F5~200,
200: D5-200 + G5~200 + B5^200,
200: E4/200 + C5-200 + F5~200,
200: B4-200 + E5~200,
200: E4/200 + A4-200 + D5~200,
200,
200: D4/200 + A4-200 + D5~200,
200: B4-200 + E5~200 + G5^200,
200: E4/200 + A4-200 + D5~200,
200`, Infinity)

let selectedMap = 0;
const maps = [
  map`
......
......
......
......
......`,
  map`
....2.
......
......
......
...b..`,
  map`
......
......
......
......
......`
]

setBackground(background)

const startScreen = () => {
  clearText()
  selectedMap = 0;
  setMap(maps[selectedMap])

  addText("Catch the Egg", { y: 3, color: color`2` })
  addText("By Jonak", { y: 5, color: color`L` })
  addText("Press 'J'", { y: 11, color: color`0` })
}

const endScreen = (maxHit) => {
  clearText()
  selectedMap = 2;
  setMap(maps[selectedMap])

  addText(maxHit ? "You're Insane" : "Game Over", { y: 3, color: color`2` })
  addText(`Score: ${score}`, { y: 5, color: color`2` })
  addText("Press 'J'", { y: 11, color: color`0` })
}

class Chicken {
  constructor(position, basketPosition, direction) {
    this.pos = position;
    this.basketPos = basketPosition
    this.direction = direction;
    this.spriteIndex = -1;
    this.isActive = false;

    this.incrementSprite()
  }

  incrementSprite() {
    if (this.spriteIndex === 4) this.spriteIndex = -1
    this.spriteIndex += 1

    clearTile(this.pos.x, this.pos.y)
    addSprite(this.pos.x, this.pos.y, this.direction === "right" ? chickenRight[this.spriteIndex] : chickenLeft[this.spriteIndex])
  }

  layEgg() {
    this.isActive = true;

    const layingSteps = setInterval(() => {
      if (misses >= 2 || score === MAX_SCORE) {
        clearInterval(layingSteps);
        return;
      }

      this.incrementSprite()

      if (this.spriteIndex === 0) {
        clearInterval(layingSteps)

        const basketInstance = getFirst(basket)
        const basketPos = { x: basketInstance.x, y: basketInstance.y }

        if (basketPos.x === this.basketPos.x && basketPos.y === this.basketPos.y) {
          playTune(tune`
109.89010989010988: A5-109.89010989010988 + D5~109.89010989010988 + G4/109.89010989010988,
109.89010989010988: A5-109.89010989010988 + D5~109.89010989010988 + G4/109.89010989010988,
3296.7032967032965`)
          score += 1;
          addText(score.toString(), { x: 2, y: 1, color: color`2` })
          if (score === MAX_SCORE) setTimeout(() => { endScreen(true) }, 2000)
        } else {
          misses += 1;

          if (misses === 1) {
            clearTile(4, 0);
            addSprite(4, 0, heartHalf)
            playTune(tune`
57.915057915057915: G5-57.915057915057915 + A4^57.915057915057915,
57.915057915057915,
57.915057915057915: E5-57.915057915057915 + F4^57.915057915057915,
1679.5366795366795`)
          } else if (misses === 2) {
            clearTile(4, 0)
            addSprite(4, 0, heartEmpty)
            playTune(tune`
144.92753623188406: B5^144.92753623188406 + D5-144.92753623188406 + F4/144.92753623188406,
144.92753623188406: G5^144.92753623188406 + B4-144.92753623188406 + D4/144.92753623188406,
144.92753623188406: E5^144.92753623188406 + G4-144.92753623188406 + C4/144.92753623188406,
4202.898550724638`)
            setTimeout(endScreen, 2000)
          }
        }

        this.isActive = false
      }
    }, 900)
  }
}

const gameScreen = () => {
  clearText()
  selectedMap = 1;
  setMap(maps[selectedMap])

  score = 0;
  misses = 0;

  addText(score.toString(), { x: 2, y: 1, color: color`2` })

  const chickens = [
    new Chicken({ x: 1, y: 1 }, { x: 2, y: 2 }, "right"),
    new Chicken({ x: 4, y: 1 }, { x: 3, y: 2 }, "left"),
    new Chicken({ x: 1, y: 3 }, { x: 2, y: 4 }, "right"),
    new Chicken({ x: 4, y: 3 }, { x: 3, y: 4 }, "left")
  ]

  const gameLoop = setInterval(() => {
    if (misses >= 2 || score === MAX_SCORE) {
      clearInterval(gameLoop);
      return
    }

    const nonActiveChickens = chickens.filter((chicken) => !chicken.isActive)

    if (nonActiveChickens.length > 0) {
      nonActiveChickens[Math.floor(Math.random() * nonActiveChickens.length)].layEgg()
    }
  }, 1200)
}

startScreen()

onInput("w", () => {
  if (misses >= 2) return;
  const basketInstance = getFirst(basket)
  if (basketInstance.y !== 2) basketInstance.y -= 2
})

onInput("a", () => {
  if (misses >= 2) return;
  const basketInstance = getFirst(basket)
  if (basketInstance.x !== 2) basketInstance.x -= 1
})

onInput("s", () => {
  if (misses >= 2) return;
  const basketInstance = getFirst(basket)
  if (basketInstance.y !== 4) basketInstance.y += 2
})

onInput("d", () => {
  if (misses >= 2) return;
  const basketInstance = getFirst(basket)
  if (basketInstance.x !== 3) basketInstance.x += 1
})

onInput("j", () => {
  if (selectedMap === 0) gameScreen()
  else if (selectedMap === 2) startScreen()
})
